﻿using System.Collections.Generic;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using RK.Common.GraphicsEngine.Objects;
using RK.WpfModelViewer.Infrastructure;
using WinForms = System.Windows.Forms;

namespace RK.WpfModelViewer.Modules.ACImporter
{
    public class XModelImporter : IModelImporter
    {
        public ObjectType ImportObjectType(string filePath)
        {
            List<VertexStructure> vertexStructures = new List<VertexStructure>();

            using (WinForms.Control dummyControl = new WinForms.Control())
            {
                dummyControl.Width = 50;
                dummyControl.Height = 50;
                dummyControl.CreateControl();

                //Read all geometry of the mesh
                ExtendedMaterial[] materialInformation = null;
                using (Device device = new Device(0, DeviceType.Hardware, dummyControl.Handle, CreateFlags.SoftwareVertexProcessing, new PresentParameters[]
                    {
                        new PresentParameters()
                        {
                            DeviceWindow = dummyControl,
                            MultiSample = MultiSampleType.None,
                            MultiSampleQuality = 0,
                            BackBufferWidth = 50,
                            BackBufferHeight = 50,
                            AutoDepthStencilFormat = DepthFormat.D16,
                            Windowed = true,
                            SwapEffect = SwapEffect.Discard,
                            PresentationInterval = PresentInterval.Immediate,
                            EnableAutoDepthStencil = true
                        }
                    }))
                using (Mesh mesh = Mesh.FromFile(filePath, MeshFlags.Managed, device, out materialInformation))
                using (Mesh clonedMesh = mesh.Clone(MeshFlags.Managed, CustomVertex.PositionColoredTextured.Format, device))
                using (GraphicsStream vertexStream = clonedMesh.LockVertexBuffer(LockFlags.None))
                using (GraphicsStream indexStream = clonedMesh.LockIndexBuffer(LockFlags.None))
                {
                    CustomVertex.PositionColoredTextured[] vertices = vertexStream.Read(typeof(CustomVertex.PositionColoredTextured), clonedMesh.NumberVertices)
                        as CustomVertex.PositionColoredTextured[];
                    ushort[] indices = indexStream.Read(typeof(ushort), clonedMesh.NumberFaces * 3)
                        as ushort[];

                    AttributeRange[] attributeTable = clonedMesh.GetAttributeTable();
                    for (int loopSubset = 0; loopSubset < attributeTable.Length; loopSubset++)
                    {
                        AttributeRange actRange = attributeTable[loopSubset];
                        VertexStructure newVertexStructure = new VertexStructure();
                        for (int loopVertex = actRange.VertexStart; loopVertex < actRange.VertexStart + actRange.VertexCount; loopVertex++)
                        {
                            newVertexStructure.AddVertex(new Vertex(
                                ToCommonVector(vertices[loopVertex].Position),
                                new Common.Color4(vertices[loopVertex].Color),
                                new Common.Vector2(vertices[loopVertex].Tu, vertices[loopVertex].Tv)));
                        }

                        for (int loopIndex = actRange.FaceStart * 3; loopIndex < actRange.FaceStart * 3 + actRange.FaceCount * 3; loopIndex += 3)
                        {
                            newVertexStructure.AddTriangle(
                                indices[(loopIndex - actRange.FaceStart * 3)],
                                indices[(loopIndex - actRange.FaceStart * 3) + 1],
                                indices[(loopIndex - actRange.FaceStart * 3) + 2]);
                        }
                        vertexStructures.Add(newVertexStructure);
                    }
                }

                //Read all material properties
                for (int loopMaterial = 0; loopMaterial < materialInformation.Length; loopMaterial++)
                {
                    ExtendedMaterial actExMaterial = materialInformation[loopMaterial];
                    if (vertexStructures.Count > loopMaterial)
                    {
                        VertexStructure targetVertexStructure = vertexStructures[loopMaterial];
                        targetVertexStructure.Material = actExMaterial.TextureFilename;
                        targetVertexStructure.MaterialProperties.TextureName = actExMaterial.TextureFilename;
                        targetVertexStructure.MaterialProperties.AmbientColor = new Common.Color4(actExMaterial.Material3D.Ambient);
                        targetVertexStructure.MaterialProperties.DiffuseColor = new Common.Color4(actExMaterial.Material3D.Diffuse);
                        targetVertexStructure.MaterialProperties.EmissiveColor = new Common.Color4(actExMaterial.Material3D.Emissive);
                        targetVertexStructure.MaterialProperties.Shininess = actExMaterial.Material3D.SpecularSharpness;
                        targetVertexStructure.MaterialProperties.Specular = new Common.Color4(actExMaterial.Material3D.Specular);
                    }
                }
            }

            return new GenericObjectType(vertexStructures.ToArray());
        }

        public Common.Vector3 ToCommonVector(Vector3 directXVector)
        {
            return new Common.Vector3(
                directXVector.X,
                directXVector.Y,
                directXVector.Z);
        }

        /// <summary>
        /// Gets the get file dialog filter.
        /// </summary>
        /// <value>
        /// The get file dialog filter.
        /// </value>
        public string GetFileDialogFilter
        {
            get
            {
                return "DirectX X-Files (*.x)|*.x";
            }
        }
    }
}